// Copyright 2009 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Author: Jeff Stewart
//
// Implements an adapter for RenamableSslSocket to do line-based reading with
// timeouts.

#include <QtCore/QTime>

#include "probes/linereader.h"
#include "util/common.h"

namespace popdiag {

LineReader::LineReader(RenamableSslSocket *src, int timeoutInMillis)
    : src_(src),
      accum_(),
      timeout_(timeoutInMillis),
      timer_(new QTimer(this)) {
  CHECK(connect(src_, SIGNAL(readyRead()),
                this, SLOT(OnDataReady())));
  CHECK(connect(timer_, SIGNAL(timeout()),
                this, SLOT(OnTimeout())));
  timer_->setSingleShot(true);
  timer_->start(timeout_);
}

LineReader::~LineReader() {
}

void LineReader::Cleanup() {
  timer_->stop();
  src_->disconnect(this);
}

void LineReader::OnTimeout() {
  Cleanup();
  emit DataReady(TIMEOUT);
}

bool LineReader::NonblockingRead(QString *out) {
  if (ReadFromAccum(out)) {
    return true;
  }
  TryRead(false);
  return ReadFromAccum(out);
}

void LineReader::OnDataReady() {
  TryRead(true);
}

void LineReader::TryRead(bool send_signals) {
  char workbuf[1024];
  bool anything_read = false;
  while (true) {
    qint64 bytes_read = src_->read(workbuf, sizeof(workbuf));
    if (bytes_read < 0) {
      emit DataReady(SOCKET_DROPPED);
      return;
    }
    if (bytes_read == 0) {      break;
    }
    anything_read = true;
    // We have a bit of a problem here.  We want to read data, but it
    // might be coming out of the middle of an 8-bit mail message using
    // an unknown encoding.  And our read might land in the middle of it.
    // I'm not at all sure what we can do about that.  We'll probably
    // eventually have to add support for interpretting the first line
    // and just reading and eating the rest as 8-bit opaque data.  Even that
    // has to be appended on UTF character at a time and will be troublesome.
    // We'll be back to re-examine this when we get enough international
    // coverage here.
    // TODO: Figure out how to read i18n pop message properly.
    accum_.append(QString::fromUtf8(workbuf, bytes_read));
  }
  if (anything_read) {
    if (send_signals) {
      emit DataReady(DATA_READ);
    }
  }
}

bool LineReader::ReadFromAccum(QString *out) {
  int index = accum_.indexOf(QChar('\n'));
  if (index == -1) {
    return false;
  }
  *out = accum_.mid(0, index + 1);
  accum_ = accum_.mid(index + 1);
  timer_->start(timeout_);
  return true;
}

void RenamableSslSocket::connectToHost(const QHostAddress &address,
                                       quint16 port) {
  QSslSocket::connectToHost(address, port);
}

qint64 RenamableSslSocket::write(const QByteArray &byteArray) {
  return QSslSocket::write(byteArray);
}

void RenamableSslSocket::startClientEncryption() {
  QSslSocket::startClientEncryption();
}

bool RenamableSslSocket::flush() {
  return QSslSocket::flush();
}

}  // namespace popdiag
